Service Worker,其主要作用是作为一个网页与Web服务器间的代理服务器。它可以缓存资源,并在网页请求对应资源时,劫持网页请求,直接返回已缓存的资源,从而节省网络加载时间,以及在无网络条件下正常加载页面。
整体工作流程如下:
加载并执行主线程JavaScript,主线程调用serviceWorkerContainer.register()
注册service worker
serviceWorkerContainer.register()
包含两个参数,第一个参数是指定service worker脚本的url地址第二个参数为可选配置项resolve
方法对service worker进行检测,也可以指定reject
方法捕获错误ServiceWorkerGlobalScope
的执行上下文中被执行,这个执行环节是独立于主线程的,无DOM操作权限。install
事件,这个事件表示service worker的安装,可以在此事件的事件处理器中执行建立IndexedDB
、初始化缓存内容的事务。install
事件的事件处理器执行完毕后,即表示此service worker已安装activate
事件,activate事件主要用来清理老版本service worker的过期资源,从而达到释放存储空间等目的。在这之后,service worker即会正式接管页面
fetch
事件,将请求移交给service worker,service worker内部可以通过注册fetch
事件处理器,来处理网页请求结合MDN上的一个实例来说明一下service worker的工作流程,具体代码可见github仓库。
navigator.serviceWorker.register
注册service worker,将文件sw.js
中的脚本加载进service worker的执行环境进行执行// app.js
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js').then(function(reg) {
if(reg.installing) {
console.log('Service worker installing');
} else if(reg.waiting) {
console.log('Service worker installed');
} else if(reg.active) {
console.log('Service worker active');
}
}).catch(function(error) {
// registration failed
console.log('Registration failed with ' + error);
});
}
event.waitUntil
将install延迟至watiUntil
中的内容处理完毕。在waituntil
中,初始化了一个名称为v1
的缓存器,并将页面所需资源添加至缓存器中。// sw.js
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('v1').then(function(cache) {
return cache.addAll([
'./',
'./index.html',
'./style.css',
'./app.js',
'./image-list.js',
'./star-wars-logo.jpg',
'./gallery/bountyHunters.jpg',
'./gallery/myLittleVader.jpg',
'./gallery/snowTroopers.jpg'
]);
})
);
});
fetch
事件,当网页发起请求时,浏览器会触发fetch事件,并将网络请求以event.request
的方式传递给service worker。在此处理过程中,通过cache.match
来匹配缓存器中对应的资源。如果资源已经存在,response
不为undfined,则直接将此资源返回,不再发起网络请求。若资源不存在,则通过fetch
发起网络请求,获得资源后,先通过cache.put
将资源存储至缓存器中,然后将资源返回给网页。// sw.js
self.addEventListener('fetch', function(event) {
event.respondWith(caches.match(event.request).then(function(response) {
if (response !== undefined) {
return response;
} else {
return fetch(event.request).then(function (response) {
let responseClone = response.clone();
caches.open('v1').then(function (cache) {
cache.put(event.request, responseClone);
});
return response;
}).catch(function () {
return caches.match('./gallery/myLittleVader.jpg');
});
}
}));
});
参考